# -*- coding: utf-8 -*-
# @version : 1.0
# @File    : tools.py
# @Date    : 2024/9/13 11:35
# @Author  : GlenZhao
# @Desc    : 工具
import base64
import os
import importlib
import datetime
import random
import re
import string
from io import BytesIO
from typing import List, Union
from pathlib import Path

from application import settings
from core.logger import logger


class SingletonDecorator(object):
    _instance = None

    def __init__(self, cls):
        self._cls = cls

    def __call__(self, *args, **kwargs):
        if self._instance is None:
            self._instance = self._cls(*args, **kwargs)
        return self._instance


def test_password(password: str) -> Union[str, bool]:
    """
    检测密码强度
    """
    if len(password) < 8 or len(password) > 16:
        return '长度需为8-16个字符,请重新输入。'
    else:
        for i in password:
            if 0x4e00 <= ord(i) <= 0x9fa5 or ord(i) == 0x20:  # Ox4e00等十六进制数分别为中文字符和空格的Unicode编码
                return '不能使用空格、中文，请重新输入。'
        else:
            key = 0
            key += 1 if bool(re.search(r'\d', password)) else 0
            key += 1 if bool(re.search(r'[A-Za-z]', password)) else 0
            key += 1 if bool(re.search(r"\W", password)) else 0
            if key >= 2:
                return True
            else:
                return '至少含数字/字母/字符2种组合，请重新输入。'


def list_dict_find(options: List[dict], key: str, value: any) -> Union[dict, None]:
    """
    字典列表查找
    """
    return next((item for item in options if item.get(key) == value), None)


def get_time_interval(start_time: str, end_time: str, interval: int, time_format: str = "%H:%M:%S") -> List:
    """
    获取时间间隔
    :param end_time: 结束时间
    :param start_time: 开始时间
    :param interval: 间隔时间（分）
    :param time_format: 字符串格式化，默认：%H:%M:%S
    """
    if start_time.count(":") == 1:
        start_time = f"{start_time}:00"
    if end_time.count(":") == 1:
        end_time = f"{end_time}:00"
    start_time = datetime.datetime.strptime(start_time, "%H:%M:%S")
    end_time = datetime.datetime.strptime(end_time, "%H:%M:%S")
    time_range = []
    while end_time > start_time:
        time_range.append(start_time.strftime(time_format))
        start_time = start_time + datetime.timedelta(minutes=interval)
    return time_range


def generate_string(length: int = 8) -> str:
    """
    生成随机字符串
    :param length: 字符串长度
    """
    return ''.join(random.sample(string.ascii_letters + string.digits, length))


def import_modules(modules: list, desc: str, **kwargs):
    for module in modules:
        if not module:
            continue
        try:
            # 动态导入模块
            module_pag = importlib.import_module(module[0:module.rindex(".")])
            getattr(module_pag, module[module.rindex(".") + 1:])(**kwargs)
        except ModuleNotFoundError:
            logger.error(f"AttributeError：导入{desc}失败，未找到该模块：{module}")
        except AttributeError:
            logger.error(f"ModuleNotFoundError：导入{desc}失败，未找到该模块下的方法：{module}")


async def import_modules_async(modules: list, desc: str, **kwargs):
    """
    引入模块

    :param modules:
    :param desc:
    :param kwargs:
    """
    for module in modules:
        if not module:
            continue
        try:
            # 动态引入模块
            module_pkg = importlib.import_module(module[0:module.rindex(".")])
            await getattr(module_pkg, module[module.rindex(".") + 1:])(**kwargs)
        except ModuleNotFoundError:
            logger.error(f"AttributeError：导入{desc}失败，未找到该模块：{module}")
        except AttributeError:
            logger.error(f"ModuleNotFoundError：导入{desc}失败，未找到该模块下的方法：{module}")


async def decode_base64_image(base64_str, file_extension, output) -> str:
    """
    保存base64图片
    """
    try:
        img_data = base64.b64decode(base64_str)
        now = datetime.datetime.now()
        directory_path = os.path.join(output, str(now.year), str(now.month), str(now.day), str(now.hour))
        path = Path(directory_path)
        if not path.exists():
            path.mkdir(parents=True, exist_ok=True)

        file_name = f"{generate_string()}.{file_extension}"
        file_path = os.path.join(path, file_name)
        # 将解码后的字节流写入到图片文件中
        with open(file_path, 'wb') as image_file:
            image_file.write(img_data)
            return f"{settings.UPLOAD_URL}/{now.year}/{now.month}/{now.day}/{now.hour}/{file_name}"
    except Exception as e:
        logger.error(f"Decode base64 image data error: {e}")
        return ""

async def parse_base64_image(image_data, output) -> str:

    try:
        # 分割 data URI，提取 base64 编码的图像数据
        header, encoded = image_data.split(',', 1)

        #取扩展名
        _, extension = header.split('/', 1)
        ext_name = str.replace(extension, ';base64', '')

        return await decode_base64_image(encoded, ext_name, output)
    except Exception as e:
        logger.error(f"Decode base64 image data error: {e}")
        return ""

def parse_base64_image_to_binary(image_data):

    try:
        # 分割 data URI，提取 base64 编码的图像数据
        header, base64_data = image_data.split(';base64,')
        mime_type = header.split(':')[1]
        binary_data = base64.b64decode(base64_data)
        return BytesIO(binary_data), mime_type
    except Exception as e:
        logger.error(f"Decode base64 image data error: {e}")
    return None, None

def concatenate_numbers(a, b) -> str:
    # 使用 sorted 函数排序，然后拼接字符串，并转换为整数
    return ''.join(sorted(map(str, [a, b])))

def get_dict_key_value(data: dict, key: str):
    if '.' in key:
        ks = key.split('.')
        return get_dict_key_value(data.get(ks[0]), '.'.join(ks[1:]))
    return data.get(key)

def check_dict_items_not_empty(data: dict, keys: list[str]) -> bool:
    for k in keys:
        if not get_dict_key_value(data, k):
            return False
    return True